import * as Cesium from 'cesium'
import * as dat from 'dat.gui'

const testVertex = `
  in vec3 position3DHigh;
  in vec3 position3DLow;
  in float batchId;
  in vec4 color;
  in vec3 position;
  uniform float uWaresFrequency;
  uniform float uYScale;
  uniform float uNoiseFrequency;
  uniform float uNoiseScale;
  out vec4 v_color;
  out float vElevation;

  // 随机函数
  float random(vec2 st){
      return fract(sin(dot(st.xy,vec2(12.9898,78.233)))*43758.5453123);
  }

  // 纹理旋转函数
  vec2 rotate(vec2 uv,float rotation,vec2 mid)
  {
    return vec2(
      cos(rotation)*(uv.x-mid.x)+sin(rotation)*(uv.y-mid.y)+mid.x,
      cos(rotation)*(uv.y-mid.y)-sin(rotation)*(uv.x-mid.x)+mid.y
    );
  }

  // 二维噪声函数
  float noise(in vec2 _st){
    vec2 i=floor(_st);
    vec2 f=fract(_st);
    
    // Four corners in 2D of a tile
    float a=random(i);
    float b=random(i+vec2(1.,0.));
    float c=random(i+vec2(0.,1.));
    float d=random(i+vec2(1.,1.));
    
    vec2 u=f*f*(3.-2.*f);
    
    return mix(a,b,u.x)+
    (c-a)*u.y*(1.-u.x)+
    (d-b)*u.x*u.y;
  }

  //	Classic Perlin 2D Noise
  //	by Stefan Gustavson
  //
  vec4 permute(vec4 x)
  {
    return mod(((x*34.)+1.)*x,289.);
  }

  vec2 fade(vec2 t)
  {
    return t*t*t*(t*(t*6.-15.)+10.);
  }
  
  float cnoise(vec2 P)
  {
    vec4 Pi=floor(P.xyxy)+vec4(0.,0.,1.,1.);
    vec4 Pf=fract(P.xyxy)-vec4(0.,0.,1.,1.);
    Pi=mod(Pi,289.);// To avoid truncation effects in permutation
    vec4 ix=Pi.xzxz;
    vec4 iy=Pi.yyww;
    vec4 fx=Pf.xzxz;
    vec4 fy=Pf.yyww;
    vec4 i=permute(permute(ix)+iy);
    vec4 gx=2.*fract(i*.0243902439)-1.;// 1/41 = 0.024...
    vec4 gy=abs(gx)-.5;
    vec4 tx=floor(gx+.5);
    gx=gx-tx;
    vec2 g00=vec2(gx.x,gy.x);
    vec2 g10=vec2(gx.y,gy.y);
    vec2 g01=vec2(gx.z,gy.z);
    vec2 g11=vec2(gx.w,gy.w);
    vec4 norm=1.79284291400159-.85373472095314*vec4(dot(g00,g00),dot(g01,g01),dot(g10,g10),dot(g11,g11));
    g00*=norm.x;
    g01*=norm.y;
    g10*=norm.z;
    g11*=norm.w;
    float n00=dot(g00,vec2(fx.x,fy.x));
    float n10=dot(g10,vec2(fx.y,fy.y));
    float n01=dot(g01,vec2(fx.z,fy.z));
    float n11=dot(g11,vec2(fx.w,fy.w));
    vec2 fade_xy=fade(Pf.xy);
    vec2 n_x=mix(vec2(n00,n01),vec2(n10,n11),fade_xy.x);
    float n_xy=mix(n_x.x,n_x.y,fade_xy.y);
    return 2.3*n_xy;
  }

  void main() {
    float uTime = czm_frameNumber / 60.0;
    vec4 pos = vec4(position,1.);
    float elevation = sin(pos.x*uWaresFrequency) * sin(pos.z * uWaresFrequency);
    elevation += -abs(cnoise(vec2(pos.xz * uNoiseFrequency + uTime * 3.)))* uNoiseScale;
    vElevation = elevation;
    elevation *= uYScale;
    pos.z -= elevation;
    v_color = color;
    gl_Position = czm_projection * czm_modelView * pos;
  }
`

const testFrag = `
  in vec4 v_color;
  in float vElevation;
  uniform vec2 iResolution;
  precision mediump float;
  out vec4 myFragColor;

  void main() {
    float time = fract(czm_frameNumber / 60.0);
    float elevation= vElevation * 0.5 + 0.5;
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    myFragColor = vec4(1.0 * elevation, 0.0, 1.0, 1.0);
  }
`
export default class MagicCirclePrimitive {
  constructor() {
    this.drawCommand = null
  }
  /**
   * 将经纬度坐标转换为笛卡尔坐标
   * @param {*} i 列索引
   * @param {*} j 航索引
   * @returns [pos.x, pos.y, pos.z]
   */
  transformPos(lonlat, height = 300000.0) {
    let pos = Cesium.Cartesian3.fromDegrees(...lonlat, height)
    return [pos.x, pos.y, pos.z]
  }
  /**
   * 根据坐标中心点生成周围四个点坐标
   * @param {*} v1 
   * @param {*} v2 
   * @returns 
   */
  addVector(v1, v2) {
    return [v1[0] + v2[0], v1[1] + v2[1]]
  }
  /**
   * 根据自定义Geometry生成Primitive对象
   * @returns {Cesium.Primitive}
   */
  generateWaterGeometry() {
    // 添加平移分量
    const translate = new Cesium.Cartesian3(0, 0, 10000)
    const matrixWithTranslate = Cesium.Matrix4.fromTranslation(translate, new Cesium.Matrix4())
    console.log('平移矩阵', matrixWithTranslate)
    const geometry = Cesium.EllipsoidGeometry.createGeometry(new Cesium.EllipsoidGeometry({
      radii: new Cesium.Cartesian3(500000.0, 500000.0, 1000.0),
      vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL
    }))
    /**
     * 创建将属性名称映射到唯一位置（索引）的对象 用于匹配顶点属性和着色器程序。
     * { position: 0, normal: 1, st: 2, bitangent: 3, tangent: 4, color: 5 }
     */
    console.log('water-pipeline', Cesium.GeometryPipeline.createAttributeLocations(geometry))
    return geometry
  }
  /**
   * 添加Gui控制面板
   */
  addGui(waveParams, uniformMap) {
    const gui = new dat.GUI()
    console.log('uniformMap', uniformMap)
    gui.add(waveParams, 'uWaresFrequency').name('波纹频率').min(1.0).max(50.0).step(1).onChange(v => {
      uniformMap.uWaresFrequency = () => v
    })
    
    gui.add(waveParams, 'uYScale').name('波纹缩放').min(1.0).max(1000.0).step(1).onChange(v => {
      uniformMap.uYScale = () => v
    })
    
    gui.add(waveParams, 'uNoiseFrequency').name('噪声频率').min(1.0).max(50.0).step(1).onChange(v => {
      uniformMap.uNoiseFrequency = () => v
    })
    
    gui.add(waveParams, 'uNoiseScale').name('噪声缩放').min(1.0).max(1000.0).step(1).onChange(v => {
      uniformMap.uNoiseScale = () => v
    })
  }
  /**
   * 创建DrawCommand对象，用于渲染Primitive对象。
   * @param {*} context 
   */
  createDrawCommand(context) {
    let geometry = this.generateWaterGeometry()
    let vertexArray = Cesium.VertexArray.fromGeometry({
      context: context,
      geometry: geometry,
      attributeLocations: Cesium.GeometryPipeline.createAttributeLocations(geometry)
    })
    let shaderProgram = Cesium.ShaderProgram.fromCache({
      context: context,
      vertexShaderSource: testVertex,
      fragmentShaderSource: testFrag,
      attributeLocations: Cesium.GeometryPipeline.createAttributeLocations(geometry)
    })
    // 设置波纹参数
    const waveParams = {
      uWaresFrequency: 3.0,
      uYScale: 1.0,
      uNoiseFrequency: 10.0,
      uNoiseScale: 1.0,
    }
    let uniformMap = {
      iResolution() {
        return new Cesium.Cartesian2(context.canvas.width, context.canvas.height)
      },
      // 波纹频率
      uWaresFrequency() {
        return waveParams.uWaresFrequency
      },
      // 波纹缩放
      uYScale() {
        return waveParams.uYScale
      },
      // 噪声频率
      uNoiseFrequency() {
        return waveParams.uNoiseFrequency
      },
      // 噪声缩放
      uNoiseScale() {
        return waveParams.uNoiseScale
      },
    }
    this.addGui(waveParams, uniformMap)
    let renderState = Cesium.RenderState.fromCache({
      depthTest: {
        enabled: true,
      },
      depthMask: false,
      blending: Cesium.BlendingState.ALPHA_BLEND,
    })
    this.drawCommand = new Cesium.DrawCommand({
      vertexArray: vertexArray,
      shaderProgram: shaderProgram,
      renderState: renderState,
      uniformMap: uniformMap,
      pass: Cesium.Pass.OPAQUE,
      castShadows: false,
      receiveShadows: false,
      primitiveType: Cesium.PrimitiveType.TRIANGLES,
      // 设置模型的位置，这个是固定位置
      modelMatrix : Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(107.0, 46.0))
    })
  }
  /**
   * 更新Primitive对象，将其添加到渲染队列中。
   * @param {*} framestate 
   */
  update(framestate) {
    if(this.drawCommand === null) {
      this.createDrawCommand(framestate.context)
      // console.log(framestate.commandList)   // 6个command，分别是clear，depth，stencil，pick，model，scene
    }
    framestate.commandList.push(this.drawCommand)
  }
}
